{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# QNN on Pynq\n",
    "\n",
    "This notebook covers how to use low quantized Neural Networks on Pynq for inference on MNIST dataset by using LFC network composed of 4 fully connected layers with 1024 neurons each. There are 2 networks using different precision: \n",
    "\n",
    "- LFCW1A1 using 1 bit weights and 1 activation,\n",
    "- LFCW1A2 using 1 bit weights and 2 activation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "\n",
       "require(['notebook/js/codecell'], function(codecell) {\n",
       "  codecell.CodeCell.options_default.highlight_modes[\n",
       "      'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n",
       "  Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n",
       "      Jupyter.notebook.get_cells().map(function(cell){\n",
       "          if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n",
       "  });\n",
       "});\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import bnn"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. LFC and MNIST\n",
    "\n",
    "This notebook performs inference on MNIST test set from http://yann.lecun.com/exdb/mnist/ which contains 10000 pictures of handwritten digits. The LFC network requires MNIST formatted input data, that's why the binary test file can be directly loaded. All other images have to be formatted to this specification (refer to url and LFC webcam examples).\n",
    "\n",
    "At first you need to download mnist test set and labels using wget and unzip the archive as shown below:\n",
    "In order to be able to compare the inferred classes against the expected labels we first read the labels:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10000"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#get\n",
    "!wget http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz \n",
    "!wget http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz \n",
    "#unzip    \n",
    "!gzip -d t10k-images-idx3-ubyte.gz\n",
    "!gzip -d t10k-labels-idx1-ubyte.gz\n",
    "\n",
    "#read labels\n",
    "labels = []\n",
    "with open(\"/home/xilinx/jupyter_notebooks/bnn/t10k-labels-idx1-ubyte\",\"rb\") as lbl_file:\n",
    "    #read magic number and number of labels (MSB first) -> MNIST header\n",
    "    magicNum = int.from_bytes(lbl_file.read(4), byteorder=\"big\")\n",
    "    countLbl = int.from_bytes(lbl_file.read(4), byteorder=\"big\")\n",
    "    #now the labels are following byte-wise\n",
    "    for idx in range(countLbl):\n",
    "        labels.append(int.from_bytes(lbl_file.read(1), byteorder=\"big\"))\n",
    "    lbl_file.close()\n",
    "len(labels)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Hardware Inference\n",
    "\n",
    "First of all a classifier needs to be instantiated. Using the LfcClassifier will allow to classify MNIST formatted images utilizing LFC network. There are two different runtimes available: hardware accelerated and pure software environment.\n",
    "\n",
    "Once a classifier is instantiated the inference on MNIST images can be started using `classify_mnist` or `classify_mnists` methods - for both single and multiple images."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Case 1: \n",
    "##### W1A1 - 1 bit weights and 1 bit activation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lfcW1A1_classifier = bnn.LfcClassifier(bnn.NETWORK_LFCW1A1,\"mnist\",bnn.RUNTIME_HW)\n",
    "lfcW1A1_classifier.classes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Inference took 28040.00 microseconds, 2.80 usec per image\n",
      "Classification rate: 356633.39 images per second\n"
     ]
    }
   ],
   "source": [
    "result_W1A1 = lfcW1A1_classifier.classify_mnists(\"/home/xilinx/jupyter_notebooks/bnn/t10k-images-idx3-ubyte\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Case 2: \n",
    "#### W1A2 - 1 bit weights and 2 bit activation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "lfcW1A2_classifier = bnn.LfcClassifier(bnn.NETWORK_LFCW1A2,\"mnist\",bnn.RUNTIME_HW)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Inference took 28040.00 microseconds, 2.80 usec per image\n",
      "Classification rate: 356633.39 images per second\n"
     ]
    }
   ],
   "source": [
    "result_W1A2 = lfcW1A2_classifier.classify_mnists(\"/home/xilinx/jupyter_notebooks/bnn/t10k-images-idx3-ubyte\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3. Software accelerated inference\n",
    "\n",
    "In comparison to previous runs the inference can be performed in pure software runtime utilizing PYNQs ARM core. Let's only take the first 10 pictures to get results within a narrow time frame:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open(\"/home/xilinx/jupyter_notebooks/bnn/10_mnist_pictures\", \"wb\") as out_file:\n",
    "    with open(\"/home/xilinx/jupyter_notebooks/bnn/t10k-images-idx3-ubyte\",\"rb\") as img_file:\n",
    "        #copy magic number\n",
    "        out_file.write(img_file.read(4))\n",
    "        #set number of images\n",
    "        img_file.read(4)\n",
    "        out_file.write(bytearray.fromhex('0000000A'))        \n",
    "        #copy row and column information\n",
    "        out_file.write(img_file.read(8))\n",
    "        \n",
    "        #copy 10 pictures (one is 28x28, 1 pixel is 1 byte)\n",
    "        out_file.write(img_file.read(28*28*10))\n",
    "        img_file.close()\n",
    "        out_file.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Start inference"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "SW Inference with W1A1:\n",
      "Inference took 171891.99 microseconds, 17189.20 usec per image\n",
      "Classification rate: 58.18 images per second\n",
      "\n",
      "SW Inference with W1A2:\n",
      "Inference took 1282747.97 microseconds, 128274.80 usec per image\n",
      "Classification rate: 7.80 images per second\n"
     ]
    }
   ],
   "source": [
    "print(\"SW Inference with W1A1:\")\n",
    "sw_lfcW1A1_classifier = bnn.LfcClassifier(bnn.NETWORK_LFCW1A1,\"mnist\",bnn.RUNTIME_SW)\n",
    "sw_resultW1A1 = sw_lfcW1A1_classifier.classify_mnists(\"/home/xilinx/jupyter_notebooks/bnn/10_mnist_pictures\")\n",
    "print(\"\\nSW Inference with W1A2:\")\n",
    "sw_lfcW1A2_classifier = bnn.LfcClassifier(bnn.NETWORK_LFCW1A2,\"mnist\",bnn.RUNTIME_SW)\n",
    "sw_resultW1A2 = sw_lfcW1A2_classifier.classify_mnists(\"/home/xilinx/jupyter_notebooks/bnn/10_mnist_pictures\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As it can be seen, pure software runtime is much slower."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Summary\n",
    "\n",
    "### Inference time\n",
    "\n",
    "##### Hardware\n",
    "\n",
    "Results can be visualized using matplotlib. The inference time per image is accessible through the classifier. Here you can see hardware vs software execution times per image in microseconds:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f9faa8fd0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "hw_time = [lfcW1A1_classifier.usecPerImage,\n",
    "           lfcW1A2_classifier.usecPerImage]\n",
    "sw_time = [sw_lfcW1A1_classifier.usecPerImage,\n",
    "           sw_lfcW1A2_classifier.usecPerImage]\n",
    "\n",
    "x_axis = ('W1A1', 'W1A2')\n",
    "\n",
    "y_pos = np.arange(len(x_axis))\n",
    "plt.bar(y_pos-0.25, hw_time, 0.25)\n",
    "plt.bar(y_pos+0.25, sw_time, 0.25)\n",
    "plt.xticks(y_pos, x_axis)\n",
    "plt.legend([\"hardware\",\"software\"])\n",
    "plt.semilogy()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Accuracy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy W1A1:  98.4\n",
      "Accuracy W1A2:  98.49\n"
     ]
    }
   ],
   "source": [
    "#compare against labels\n",
    "countRight = 0\n",
    "for idx in range(len(labels)):\n",
    "    if labels[idx] == result_W1A1[idx]:\n",
    "        countRight += 1\n",
    "accuracyW1A1 = countRight*100/len(labels)\n",
    "\n",
    "countRight = 0\n",
    "for idx in range(len(labels)):\n",
    "    if labels[idx] == result_W1A2[idx]:\n",
    "        countRight += 1\n",
    "accuracyW1A2 = countRight*100/len(labels)\n",
    "\n",
    "print(\"Accuracy W1A1: \", accuracyW1A1)\n",
    "print(\"Accuracy W1A2: \", accuracyW1A2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. Reset the device"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pynq import Xlnk\n",
    "\n",
    "xlnk = Xlnk()\n",
    "xlnk.xlnk_reset()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
